<template>
  <view
    v-if="opacity > 0"
    ref="container"
    :class="['zui-watermark', renderMode]"
  >
    <div class="wrapper" :style="style">
      <div
        v-for="row in totalRow"
        :key="'row-' + row"
        class="watermark-row"
        :style="
          '--zui-watermark-overlay: ' +
          overlayOffsets[Math.floor(row % overlayStep)] +
          '%'
        "
      >
        <div
          v-for="col in totalCol + (row % overlayStep !== 0 ? 1 : 0)"
          :key="col"
          class="watermark-block"
        >
          <slot name="watermark">
            <div class="auto-generated">
              <p v-for="(line, idx) in content.split('\n')" :key="idx">
                {{ line }}
              </p>
            </div>
          </slot>
        </div>
      </div>
    </div>
    <slot></slot>
  </view>
  <view v-else class="zui-watermark none"></view>
</template>

<script>
let screenInfo = null;
if (!screenInfo) {
  const sysinfo = uni.getSystemInfoSync();
  screenInfo = {
    width: sysinfo.screenWidth,
    height: sysinfo.screenHeight,
  };
}

const BLEND_MODES = [
  "normal",
  "multiply",
  "screen",
  "overlay",
  "darken",
  "lighten",
  "color-dodge",
  "color-burn",
  "hard-light",
  "soft-light",
  "difference",
  "exclusion",
  "hue",
  "saturation",
  "color",
  "luminosity",
];

/**
 * UI 水印组件
 *
 * @slot default    默认插槽。当使用默认插槽时，组件渲染为局部水印
 * @slot watermark  自定义水印插槽。任何内容，复杂内容消耗更多资源
 */
export default {
  name: "zui-watermark",

  props: {
    /**
     * 水印文字内容
     *
     * #watermark 插槽会覆盖 content 设置
     */
    content: {
      type: String,
      default: "我是文字水印",
    },

    /**
     * 水印单元宽度
     */
    cellWidth: {
      type: Number,
      default: 120,
    },

    /**
     * 水印单元高度
     */
    cellHeight: {
      type: Number,
      default: 60,
    },

    /**
     * 旋转角度
     */
    rotation: {
      type: Number,
      default: -30,
    },

    /**
     * 排列重叠系数, [0, 1]
     */
    overlay: {
      type: Number,
      default: 0.15,
    },

    /**
     * 透明度
     */
    opacity: {
      type: Number,
      default: 0.1,
    },

    /**
     * 文字颜色
     */
    color: {
      type: String,
      default: undefined,
    },

    /**
     * 混合
     */
    blend: {
      type: [Boolean, String],
      default: false,
      validator: (val) => {
        if (typeof val === "string") {
          if (!BLEND_MODES.includes(val))
            throw new Error(
              "<zui-watermark />: blend 属性值只能是 boolean 和合法的 mix-blend-mode 值。参考链接：https://developer.mozilla.org/en-US/docs/Web/CSS/mix-blend-mode"
            );
          return true;
        }

        if (typeof val !== "boolean") {
          throw new Error(
            "<zui-watermark />: blend 属性值只能是 boolean 和合法的 mix-blend-mode 值。参考链接：https://developer.mozilla.org/en-US/docs/Web/CSS/mix-blend-mode"
          );
        }

        return true;
      },
    },

    /**
     * 水印层级
     */
    zIndex: {
      type: Number,
      default: 99999,
    },
  },

  data() {
    const hasChildren = !!this.$slots.default;
    return {
      totalRow: 0,
      totalCol: 0,
      overlayStep: 0,
      overlayOffsets: [],
      hasChildren,
      renderMode: hasChildren ? "local" : "global",
    };
  },

  computed: {
    style() {
      const style = {
        "--zui-watermark-width": `${this.cellWidth}px`,
        "--zui-watermark-height": `${this.cellHeight}px`,
        "--zui-watermark-depth": this.zIndex,
        "--zui-watermark-opacity": this.opacity,
        "--zui-watermark-rotate": `${this.rotation}deg`,
        "--zui-watermark-invert":
          this.blend === true ? "difference" : this.blend || "unset",
      };

      if (this.color) {
        style["--zui-watermark-color"] = this.color;
      }

      return Object.keys(style)
        .map((key) => `${key}:${style[key]}`)
        .join(";");
    },
  },

  created() {
    // console.log('::>> watermark::hasChildren', this.$slots);
    this._updateLayout();
  },

  methods: {
    _updateLayout() {
      this.totalRow = Math.ceil(screenInfo.height / this.cellHeight);
      this.totalCol = Math.ceil(screenInfo.width / this.cellWidth);
      this.overlayStep = Math.floor(1 / this.overlay);
      this.overlayOffsets = new Array(this.overlayStep)
        .fill(null)
        .map((_, step) => {
          const offset = step * this.overlay - 1;
          return (offset <= -1 ? 0 : offset) * 100;
        });
    },
    /**
     * 更新尺寸
     */
    updateBoundingRect() {},
  },
};
</script>

<style scoped lang="scss">
.zui-watermark {
  z-index: var(--zui-watermark-depth, 99999);
  pointer-events: none;

  &.global {
    position: fixed !important;
    top: 0;
    left: 0;
    width: 100vw;
    height: 100vh;
  }
  &.local {
    position: relative !important;
  }

  &.none {
    display: none;
  }

  > .wrapper {
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    opacity: var(--zui-watermark-opacity, 0.15);
    overflow: hidden;
    mix-blend-mode: var(--zui-watermark-invert, unset);
  }
}

.watermark-row {
  display: flex;
  flex-wrap: nowrap;
}

.watermark-block {
  display: flex;
  flex-grow: 0;
  flex-shrink: 0;
  justify-content: center;
  align-items: center;
  text-align: center;
  width: var(--zui-watermark-width);
  height: var(--zui-watermark-height);
  color: var(--zui-watermark-color, unset);
  transform: translateX(var(--zui-watermark-overlay, 0))
    rotate(var(--zui-watermark-rotate));

  p {
    font-size: 28rpx;
    line-height: 1.2em;
  }
}
</style>
